package com.fourfinance.config;

import java.util.Properties;

import javax.annotation.Resource;
import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
public class PersistenceContext {

    protected static final String PROPERTY_NAME_DATABASE_DRIVER_CLASSNAME = "jdbc.driverClassName";
    protected static final String PROPERTY_NAME_DATABASE_PASSWORD = "jdbc.password";
    protected static final String PROPERTY_NAME_DATABASE_URL = "jdbc.databaseurl";
    protected static final String PROPERTY_NAME_DATABASE_USERNAME = "jdbc.username";
    protected static final String PROPERTY_NAME_DATABASE_EMBEDDED = "jdbc.embedded";

    private static final String HIBERNATE_CONFIG_FILE = "hibernate.cfg.xml";
    private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
    private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
    
    @Resource
    private Environment environment;

    @Bean
    public DataSource dataSource() {
    	
    	if(Boolean.parseBoolean(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_EMBEDDED))){    		
    		return getEmbeddedDataSource();
    	} else {
    		return getBasicDataSource();
    	}

    }
    
    private DataSource getBasicDataSource(){
    	
    	BasicDataSource dataSource = new BasicDataSource();        
        dataSource.setDriverClassName(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER_CLASSNAME));
        dataSource.setUrl(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
        dataSource.setUsername(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
        dataSource.setPassword(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));

        return dataSource;
    }
    
    private DataSource getEmbeddedDataSource(){
    	
		return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL)
				.addScript("classpath:/sql/create-db-hsql.sql").build();  	
    }
    
    @Bean
    public LocalSessionFactoryBean sessionFactory(){
    	
    	LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
    	
    	sessionFactory.setDataSource(dataSource());
    	sessionFactory.setConfigLocation(new ClassPathResource(HIBERNATE_CONFIG_FILE));
    	sessionFactory.setHibernateProperties(getHibernateProperties());
    	
    	return sessionFactory;
    }
    
    @Bean
    public HibernateTransactionManager transactionManager(){
    	
    	HibernateTransactionManager transactionManager = new HibernateTransactionManager();
    	transactionManager.setSessionFactory(sessionFactory().getObject());
    	
    	return transactionManager;
    }
    
    private Properties getHibernateProperties(){
    	Properties hibernateProperties = new Properties();
    	hibernateProperties.setProperty(PROPERTY_NAME_HIBERNATE_DIALECT, 
    			environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
    	hibernateProperties.setProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL, 
    			environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
    	return hibernateProperties;
    }
    
}
